package com.killer.factory.impl;

import com.killer.anno.*;
import com.killer.pojo.BeanDefinition;
import com.killer.pojo.PropertyValue;
import com.killer.process.BeanPostProcessor;
import com.killer.process.impl.AbstractAutoProxyCreator;
import com.killer.utils.ClazzUtil;
import com.killer.utils.PackageSacnUtil;
import com.killer.utils.StringUtil;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class AnnotationConfigApplicationContext extends AbstractApplicationContext {

    /**
     * 通过构造方法加载配置类
     *
     * @param clazz
     */
    public AnnotationConfigApplicationContext(Class<?> clazz) throws Exception {
        //读取类上的注解
        registerBean(clazz);
        //实例化BeanPostProcessor（Bean的后置处理器），在创建bean的前后等执行
        registerBeanPostProcessors();
        //实例化bean
        initializeBean();
    }

    private void registerBeanPostProcessors() throws Exception {
        List<BeanDefinition> processors = getBeanDefinitionByType(BeanPostProcessor.class);
        for (BeanDefinition processor : processors) {
            BeanPostProcessor object=(BeanPostProcessor)getBean(processor.getId());
            //同时要注册到处理器中心中
            beanPostProcessors.add(object);
        }
    }

    private List<BeanDefinition> getBeanDefinitionByType(Class<?> clazz) {
        List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
        for (Map.Entry<String, BeanDefinition> entry : registerMap.entrySet()) {
            if (clazz.isAssignableFrom(entry.getValue().getClazz())){
                beanDefinitions.add(entry.getValue());
            }
        }
        return beanDefinitions;
    }


    /**
     * 注册所有的bean
     *
     * @param clazz
     */
    private void registerBean(Class<?> clazz) throws Exception {
        //扫描包
        parseComponentScan(clazz);
        //注册aop的beanpost处理器
        parseAopBeanPostProcess(clazz);
    }

    private void parseAopBeanPostProcess(Class<?> clazz) throws Exception {
        EnableAspectJAutoProxy aopAnno = clazz.getAnnotation(EnableAspectJAutoProxy.class);
        if (aopAnno != null) {
            //如果开启了aop支持,将AbstractAutoProxyCreator类添加到bean注册中心
            Class<?> aopClazz = AbstractAutoProxyCreator.class;
            BeanDefinition beanDefinition = new BeanDefinition(StringUtil.lowerFirstChar(aopClazz.getName()), aopClazz, parseBeanProperty(aopClazz), false);
            registerMap.put(StringUtil.lowerFirstChar(aopClazz.getName()), beanDefinition);
        }
    }

    private void parseComponentScan(Class<?> clazz) throws Exception {
        //获取类上的@ComponentScan注解
        ComponentScan componentScan = clazz.getAnnotation(ComponentScan.class);
        String packageName = componentScan.value();
        List<String> classNames = PackageSacnUtil.listAllClass(packageName);
        for (String className : classNames) {
            //加载该类
            Class<?> beanClass = Class.forName(className);
            //查看该类上有没有Component注解
            Component component = beanClass.getAnnotation(Component.class);
            //如果没有则不需要，跳过
            if (component == null) {
                continue;
            }
            //解析类上注入的字段
            List<PropertyValue> propertyValues = parseBeanProperty(beanClass);
            //读取是否有自定义beanId
            String beanId = component.value();
            //没有则那类名的首字母小写当id
            if (StringUtil.isBlank(beanId)) {
                beanId = StringUtil.lowerFirstChar(beanClass.getName());
            }
            List<String> registerNames = getBeanIds(beanId, beanClass);
            for (String registerName : registerNames) {
                //添加到bean注册中心中
                registerMap.put(registerName, new BeanDefinition(registerName, beanClass, propertyValues, checkNeedProxy(beanClass)));
            }
        }
    }

    /**
     * 判断该bean是否需要产生代理对象
     * @param beanClass
     * @return
     */
    private boolean checkNeedProxy(Class<?> beanClass) {
        //获取该类所有方法
        Method[] methods = beanClass.getMethods();
        if (methods != null) {
            for (Method method : methods) {
                //只要有一个方法有Transaction注解，则需要生成代理对象
                if (method.getAnnotation(Transaction.class) != null) {
                    return true;
                }
            }
        }
        return false;
    }


    private List<PropertyValue> parseBeanProperty(Class clazz) throws Exception {
        //获取该类所有的字段
        Field[] fields = clazz.getDeclaredFields();
        List<PropertyValue> propertyValues = new ArrayList<PropertyValue>();
        if (fields != null) {
            for (Field field : fields) {
                //查看file上时候有value注解
                Value varAnno = field.getAnnotation(Value.class);
                if (varAnno != null) {
                    //有value为直接赋值
                    propertyValues.add(new PropertyValue(field.getName(), varAnno.value(), null));
                } else {
                    //查看是否有Autowired注解
                    Autowired refAnno = field.getAnnotation(Autowired.class);
                    if (refAnno != null) {
                        //获取字段的类型
                        Class<?> fieldClass = field.getType();
                        //这里注入某人是以该类型的全限定类名的小写作为id
                        propertyValues.add(new PropertyValue(field.getName(), null, StringUtil.lowerFirstChar(fieldClass.getTypeName())));
                    }
                }

            }
        }
        return propertyValues;
    }


    /**
     * 该方法xml模式下暂时没有实现
     *
     * @param classType
     * @param <T>
     * @return
     * @throws Exception
     */
    @Override
    public <T> T getBean(Class<T> classType) throws Exception {
        return (T) getBean(StringUtil.lowerFirstChar(classType.getName()));
    }
}
